#pragma once


#include "app.hpp"


namespace beef {

    class InterfaceBase {
       private:
        bool _active;

       protected:
        // 等待指定时间
        void wait_for(TimeType t) {
            TimeCycle tc;

            while (tc.wait(t)) {
                tick();
            }
        }

        // 等待，直到条件为true
        void wait_for(bool (*is_true)()) {
            while (!is_true()) {
                tick();
            }
        }

        /**
         * @brief 一边等待条件变为true，一边继续执行延时任务
         *
         * 用法：while(wait_until(should_exit == true));
         *
         * @param is_true
         * @return true
         * @return false
         */
        bool wait_until(bool is_true) {
            tick();
            return !is_true;
        }

        // 界面中必须实时处理的交互操作，为了方便，不放进延时任务里
        virtual void poll() {}

        /**
         * @brief 执行界面逻辑
         *
         * 返回值可用于切换同级的其他界面
         *
         * @return int
         */
        virtual int show() = 0;

        /**
         * @brief 界面激活后只执行一次的初始化操作
         *
         * 如果sub != nullptr，表示控制权正在从这个次级界面返回，否则表示界面是从顶层激活的。
         * 
         * init 运行时，active 返回false，poll 不会执行。
         *
         * @param sub
         */
        virtual void init(InterfaceBase *sub) = 0;


        /**
         * @brief 将控制权转移给次级界面
         *
         * 切换到次级界面后还要处理返回时的逻辑，和界面被激活时一样，会先调用init。
         *
         * @param sub
         */
        int enter(InterfaceBase *sub) {
            _active = false;
            int r = sub->enter();
            init(sub);
            _active = true;
            return r;
        }

       public:
        InterfaceBase() {}

        /**
         * @brief 激活界面，执行界面逻辑
         *
         * 界面被激活时，先执行init 过程，再调用show 进入界面loop
         *
         */
        int enter() {
            init(nullptr);
            _active = true;
            int r = show();
            _active = false;
            return r;
        }

        bool active() const {
            return _active;
        }

        void tick() {
#ifndef _BETWEEN_FACE_NO_DCB
            dcb.tick();
#endif
            if (_active) {
                poll();
            }
        }
    };

}  // namespace beef